#include "Utilities.h"
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>

#include <ctime>
#include <cstdlib>
#include <cstring>
std::string getHomePath()
{
	return getenv("HOME");
}

SVector getPaths()
{
	SVector paths;
	std::string path = getenv("PATH");
	size_t i = 0;
	while( (i = path.find_first_of(':',i) ) != std::string::npos)
	{
		paths.push_back(path.substr(0,i));
		path = path.substr(i+1);
		i=0;
	}
	return paths;
}

bool checkPathExists(std::string path,std::string base)
{
	struct stat st;
	int stat_ret;
	if(base != "")
		path = path + "/" + base;
	stat_ret = stat(path.c_str(),&st);
	return !stat_ret;
}

bool checkPathIsDir(std::string path,std::string base)
{
	struct stat st;
	int stat_ret;
	if(base != "")
		path = path + "/" + base;
	stat_ret = stat(path.c_str(),&st);
	if(!stat_ret)
		return S_ISDIR(st.st_mode);
	return false;
}

bool checkPathIsFile(std::string path,std::string base)
{
	struct stat st;
	int stat_ret;
	if(base != "")
		path = path + "/" + base;
	stat_ret = stat(path.c_str(),&st);
	if(!stat_ret)
		return S_ISREG(st.st_mode)||S_ISLNK(st.st_mode);
	return false;
}

bool checkFileIsExec(std::string path,std::string base)
{
	if(checkPathIsFile(path,base))
	{
		struct stat st;
		int stat_ret;
		if(base != "")
			path = path + "/" + base;
		stat_ret = stat(path.c_str(),&st);
		if(stat_ret)
			return false;
		return (S_IXUSR|S_IXOTH|S_IXGRP)&st.st_mode;
	}
	return false;
}

std::string getFileModTime(std::string path)
{
	struct stat st;
	struct tm mtm;
	std::ostringstream oss;
	stat(path.c_str(),&st);
	mtm = *gmtime(&(st.st_mtime));
	oss.width(3);
	oss << mtm.tm_yday << "#";
	oss.width(3);
	oss << mtm.tm_year << "_";
	oss.width(2);
	oss << mtm.tm_hour << ":";
	oss.width(2);
	oss << mtm.tm_min << ":";
	oss.width(2);
	oss << mtm.tm_sec;
	return oss.str();
}

SVector getPathFiles(std::string path,std::string base)
{
	SVector filev;
	struct dirent ** filep;
	int files;
	std::string cdir = ".";
	std::string pdir = "..";
	if(base != "")
		path = path + "/" + base;
	if( (files = scandir(path.c_str(),&filep,0,alphasort)) > 0)
	{
		for( int file = 0 ; file < files ; file++ )
		{
			if(cdir != filep[file]->d_name && pdir != filep[file]->d_name)
				filev.push_back(filep[file]->d_name);
			free(filep[file]);
		}
		free(filep);
	}
	return filev;
}

bool createPath(std::string path,std::string base)
{
	struct stat st;
	int stat_ret;
	if(base != "")
		path = path + "/" + base;
	if(path == "/")
		return true;
	//Not root
	errno = 0;
	stat_ret = stat(path.c_str(),&st);
	if(!stat_ret)
		return S_ISDIR(st.st_mode);
	//stat failed
	if(errno == EACCES)
		return false;
	//Have access/can create
	if(!createPath(path.substr(0,path.find_last_of('/'))))
		return false;	//Couldnt create parent directory
	return !mkdir(path.c_str(),0744);
}

int getSelection(const char * selected,const char ** selections,int options)
{
	int opt = 0;
	for(;opt < options ; opt++)
	{
		if(strcmp(selected,selections[opt]) == 0)
			return opt;
	}
	return options;
}

std::ostream & operator<<(std::ostream & os,const ValueTable & vt)
{
	for(size_t cnt = 0 ; cnt < vt.size() ; cnt++)
		os << vt[cnt].first << "\t";
	os << std::endl;
	for(size_t row = 0 ; row < vt[0].second.size() ; row++)
	{
		for(size_t cnt = 0 ; cnt < vt.size() ; cnt++ )
		{
			if(row < vt[cnt].second.size())
				os << vt[cnt].second[row] << "\t";
			else
				os << "(NULL)\t";
		}
		os << std::endl;
	}
	return os;
}

SWPair makeSWPair(std::string column,std::string row[],size_t rows)
{
	SWPair val = std::make_pair(column,std::vector<std::string>());
	for(size_t cnt = 0 ; cnt < rows ; cnt++)
	{
		val.second.push_back(row[cnt]);
	}
	return val;
}

void operator+=(ValueTable & vt,const SWPair & pair)
{
	vt.push_back(pair);
}

int redirectFd(int old_fd,int new_fd)
{
	return dup2(new_fd,old_fd);
}

int redirectFd(int old_fd,std::string file)
{
	//|O_TTY_INIT
	mode_t fmode = S_IRWXU|S_IRWXG;
	int fd = open(file.c_str(),O_RDWR|O_CREAT,fmode);
	if(fd >= 0)
	{
		return redirectFd(old_fd,fd);
	}
	return -1;
}